package com.thug.engine;

import java.util.ArrayList;
import java.util.Stack;

import org.anddev.andengine.entity.modifier.PathModifier.Path;
import org.anddev.andengine.entity.shape.Shape;
import org.anddev.andengine.extension.physics.box2d.PhysicsFactory;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.util.MathUtils;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef;

public final class Utility {

	public static class BodyDesc {
		float mDensity;
		float mElasticity;
		float mFriction;
		boolean mSensor;
		int mBodyType;
		int mBodyShape;
		Shape mEntityShape;

		public BodyDesc(float density, float elasticity, float friction, boolean sensor, int bodyType, int bodyShape, Shape entityShape) {
			set(density, elasticity, friction, sensor, bodyType, bodyShape, entityShape);
		}

		public void set(float density, float elasticity, float friction, boolean sensor, int bodyType, int bodyShape, Shape entityShape) {
			mDensity = density;
			mElasticity = elasticity;
			mFriction = friction;
			mSensor = sensor;
			mBodyType = bodyType;
			mBodyShape = bodyShape;
			mEntityShape = entityShape;
		}
	}

	/**
	 * method to convert physics world coordinates into screen coordinates
	 * @param point
	 * @return
	 */
	public static Vector2 worldtoSceneCoord(final Vector2 point) {
		final float ptmRatio = SceneManager.PIXEL_TO_METER_RATIO;
		Vector2 vec = new Vector2(point.x * ptmRatio, point.y * ptmRatio);
		return vec;
	}

	/**
	 * method to convert screen coordinates into physics world coordinates
	 * @param point
	 * @return
	 */
	public static Vector2 scenetoWorldCoord(final Vector2 point) {
		final float ptmRatio = SceneManager.PIXEL_TO_METER_RATIO;
		Vector2 vec = new Vector2(point.x / ptmRatio, point.y / ptmRatio);
		return vec;
	}

	public static Body createBody(SceneManager sceneMgr, BodyDesc desc) {
		Body body = null;
		PhysicsWorld world = sceneMgr.getPhysicsWorld();
		float ptmRatio = SceneManager.PIXEL_TO_METER_RATIO;


		FixtureDef def = PhysicsFactory.createFixtureDef(desc.mDensity, desc.mElasticity, desc.mFriction, desc.mSensor);

		/* body type */
		BodyType bdtype = BodyType.StaticBody;
		if(desc.mBodyType == 1)
			bdtype = BodyType.DynamicBody;
		else if(desc.mBodyType == 2)
			bdtype = BodyType.StaticBody;
		else if(desc.mBodyType == 3)
			bdtype = BodyType.KinematicBody;

		/* body shape */
		if(desc.mBodyShape == 1)
			body = PhysicsFactory.createBoxBody(world, desc.mEntityShape, bdtype, def, ptmRatio);
		else if(desc.mBodyShape == 2)
			body = PhysicsFactory.createCircleBody(world, desc.mEntityShape, bdtype, def, ptmRatio);

		return body;
	}

	public static void updateBody(Body body, Shape shape, boolean posUpdate, boolean rotUpdate) {

		final float ptmRatio = SceneManager.PIXEL_TO_METER_RATIO;
		
		Vector2 pos = body.getPosition();
		float angle = body.getAngle();

		// update position
		if(posUpdate) {
			float x = shape.getX();
			float y = shape.getY();
			
			float ShapeHalfBaseWidth = shape.getWidth() * 0.5f;
			float ShapeHalfBaseHeight = shape.getHeight() * 0.5f;
			
			pos.x = x / ptmRatio + ShapeHalfBaseWidth;
			pos.y = y / ptmRatio + ShapeHalfBaseHeight;
		}

		// update rotation
		if(rotUpdate) {
			angle = MathUtils.degToRad(shape.getRotation());
		}
		
		body.setTransform(pos, angle);
	}

	public static void updateSprite(Shape shape, Body body, boolean posUpdate, boolean rotUpdate){

		final float ptmRatio = SceneManager.PIXEL_TO_METER_RATIO;

		// update position
		if(posUpdate) {
			final Vector2 pos = body.getPosition();
			float ShapeHalfBaseWidth = shape.getWidth() * 0.5f;
			float ShapeHalfBaseHeight = shape.getHeight() * 0.5f;
			shape.setPosition(pos.x * ptmRatio - ShapeHalfBaseWidth, 
					pos.y * ptmRatio - ShapeHalfBaseHeight);
		}

		// update rotation
		if(rotUpdate) {
			final float angle = body.getAngle();
			shape.setRotation(MathUtils.radToDeg(angle));
		}
	}

	/*public static Vector2D toVector2D(Vector2 vec) {
		return (new Vector2D(vec.x, vec.y));
	}

	public static Vector2 toVector2(Vector2D vec){
		return (new Vector2((float)vec.mX, (float)vec.mY));
	}*/

	public static Path reversePath(Path inputPath) {
		Stack<Vector2> mWaypoints = new Stack<Vector2>();

		for(int i = 0; i < inputPath.getSize(); i++) {
			float x = inputPath.getCoordinatesX()[i];
			float y = inputPath.getCoordinatesY()[i];
			mWaypoints.push(new Vector2(x, y));
		}

		Path path = new Path(mWaypoints.size());
		while(!mWaypoints.isEmpty()) {
			Vector2 v = mWaypoints.pop();
			path.to(v.x, v.y);
		}
		return path;
	}
	
	public static Path genReversePath(ArrayList<Vector2> points, float xOffset, float yOffsey) {
		Path path = new Path(points.size());
		Vector2 point;
		for(int i = points.size() - 1; i >= 0; i--) {
			point = points.get(i);
			float x = point.x + xOffset;
			float y = point.y + yOffsey;
			path.to(x, y);
		}
		return path;
	}
	
	public static Path addOffsetToPath(Path path, float xOffset, float yOffsey) {
		Path newpath = new Path(path.getSize());
		for(int i = 0; i < path.getSize(); i++) {
			float x = path.getCoordinatesX()[i] + xOffset;
			float y = path.getCoordinatesY()[i] + yOffsey;
			newpath.to(x, y);
		}
		
		return newpath;
	}
}
